﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Input;
using System.Windows;
using System.Reflection;
using FireFly;
using System.ComponentModel;

namespace FireFly
{
    /// <summary>
    /// Warning! this class is not realy tested yet
    /// </summary>
    [Serializable]
    public sealed class EventHook : DependencyObject
    {
        static MethodInfo _OnEventRaisedInfo = typeof(EventHook).GetMethod("OnEventRaised", BindingFlags.NonPublic | BindingFlags.Instance);
        static Dictionary<string, EventInfo> _events = new Dictionary<string, EventInfo>();
        static Dictionary<string, PropertyInfo> _commands = new Dictionary<string, PropertyInfo>();
        Delegate _handler = null;
        //public static DependencyProperty CommandProperty = DependencyProperty.Register("Command",
        //    typeof(ICommand), typeof(EventHook));\
        //Delegate _delegate;

        public EventHook()
        {
        }

        #region Properties
        //[Bindable(true)]
        public ICommand Command { get; set; }
        public string CommandName { get; set; }
        public string EventName { get; set; }
        public object CommandParameter { get; set; }
        #endregion

        internal void SetObject(DependencyObject obj)
        {
            var objType = obj.GetType();

            var eventKey = objType.FullName + "_" + EventName;

            if(!_events.ContainsKey(eventKey))
                _events.Add(eventKey, objType.GetEvent(EventName));

            var ev = _events[eventKey];
            _handler = Delegate.CreateDelegate(ev.EventHandlerType, this, _OnEventRaisedInfo);
            ev.AddEventHandler(obj, _handler);
        }

        internal void ClearObject(DependencyObject obj)
        {
            var eventKey = obj.GetType().FullName + "_" + EventName;
            if(_events.ContainsKey(eventKey))
            {
                var ev = _events[eventKey];
                ev.RemoveEventHandler(obj, _handler);
            }
        }

        void OnEventRaised(object sender, EventArgs args)
        {
            var command = Command;
            if(command == null)
            {
                var dataContext = GetDataContext(sender);
                var objType = dataContext.GetType();
                string commandKey = objType.FullName + "" + CommandName;

                if(!_commands.ContainsKey(commandKey))
                    _commands.Add(commandKey, objType.GetProperty(CommandName));

                command = (ICommand)_commands[commandKey].GetValue(dataContext, null);
            }

            if(command != null)
            {
                object param = CommandParameter;
                if(command is IRelayCommand && param == null)
                {
                    param = sender;
                }

                if(command.CanExecute(param))
                    command.Execute(param);

            }
        }

        object GetDataContext(object _object)
        {
            var obj = _object as FrameworkElement;
            if(obj != null)
            {
                return obj.DataContext;
            }
            else
            {
                var obj2 = _object as FrameworkContentElement;
                if(obj2 != null)
                    return obj2.DataContext;
            }
            return null;
        }
    }
}
